/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.mzk.oai.metadataRepository.cli;

import cz.mzk.oai.metadataRepository.metadata.MarcRecord;
import cz.mzk.oai.metadataRepository.metadata.MetadataFormat;
import cz.mzk.oai.metadataRepository.repository.AlephBase;
import cz.mzk.oai.metadataRepository.repository.Repository;
import cz.mzk.oai.metadataRepository.repository.collections.MarcBasedCollectionSelector;
import cz.mzk.oai.metadataRepository.repository.collections.MetadataCollection;
import cz.mzk.oai.metadataRepository.repository.collections.NoCollectionFoundException;
import cz.mzk.oai.metadataRepository.repository.records.Record;
import cz.mzk.oai.metadataRepository.repository.records.presentAndDeleted.PresentRecord;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.dom4j.Document;

/**
 *
 * @author Martin Řehánek (rehan at mzk.cz)
 */
public class ScanCollectionAction extends Action {

    private static final Logger logger = Logger.getLogger(ScanCollectionAction.class.getName());
    private final String collectionName;
    private final MarcBasedCollectionSelector selector;
    private final AlephBase alephBase;

    public ScanCollectionAction(Repository repository, String collectionName, String alephBase) {
        super(repository);
        this.collectionName = collectionName;
        this.selector = new MarcBasedCollectionSelector(repository);
        this.alephBase = AlephBase.valueOf(alephBase);
    }

    @Override
    public void run() throws Exception {
        MetadataCollection collection = repository.findCollection(collectionName);
        if (collection == null) {
            throw new Exception("No such collection '" + collectionName + "'");
        }
        List<Record> records = collection.getRecords(MetadataFormat.marc21, null, null);
        int counter = 0;
        for (Record record : records) {
            if (!record.isDeleted() && collection.itemsCanBeMovedFromHere()) {
                handleCounter(++counter);
                moveToOtherCollectionIfPossible((PresentRecord) record, collection);
            } else {
                logger.log(Level.INFO, "Item {0} is deleted, not moving", record.getId());
            }
        }
    }

    private void moveToOtherCollectionIfPossible(PresentRecord record, MetadataCollection recentCollection) {
        if (!record.isDeleted()) {
            try {
                Document marcMetadataDoc = record.getMetadata();
                MetadataCollection newCollection = selectCollection(marcMetadataDoc);
                if (!newCollection.getName().equals(recentCollection.getName())) {
                    repository.moveItemBetweenCollections(record.getId(), recentCollection, newCollection);
                    logger.log(Level.INFO, "Item {0} moved from collection {1} to collection {2}", new Object[]{record.getId().toString(), recentCollection.getName(), newCollection.getName()});
                } else {
                    logger.log(Level.INFO, "Item {0} stays in collection {1}", new Object[]{record.getId().toString(), recentCollection.getName()});
                }
            } catch (IOException ex) {
                logger.log(Level.SEVERE, "Failed to read marc21 record of item {0}", record.getId().toString());
            } catch (NoCollectionFoundException ex) {
                logger.log(Level.SEVERE, "No fit collection found for item {0}", record.getId().toString());
            }
        }
    }

    private MetadataCollection selectCollection(Document marcMetadataDoc) throws NoCollectionFoundException {
        MarcRecord marcRecord = new MarcRecord(marcMetadataDoc);
        return selector.chooseCollectionOrThrowException(marcRecord, alephBase);
    }

    private void handleCounter(int counter) {
        if (counter % 50 == 0) {
            System.gc();
        }
        if (counter % 100 == 0) {
            logger.log(Level.INFO, "processed {0} records", counter);
        }
    }
}
